package com.ctg.behavior.calc.impala.builder.event;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.ctg.behavior.calc.impala.report.event.CtCalcEventMeasureReport;
import com.ctg.behavior.calc.impala.utils.CtCalcRowsUtils;
import com.ctg.behavior.calc.utils.CtCalcPropertyUtils;
import com.ctg.behavior.common.calc.CtCalcPropertyType;
import com.ctg.behavior.common.consts.CtCalcConsts;
import com.ctg.behavior.common.consts.CtFieldConsts;
import com.ctg.behavior.common.event.CtECCommonResult;
import com.ctg.behavior.common.event.CtECCommonRow;
import com.ctg.behavior.common.event.CtECRollupResult;
import com.ctg.behavior.common.event.CtECRollupRow;
import com.ctg.behavior.common.event.CtEventCalcData;
import com.ctg.behavior.utils.CtDateUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class CtEventCalcResultBuilder {

	// KEY: seriesTime + "@" + byValues数组中的元素(使用@符号分隔连接起来)
    private static ThreadLocal<Map<String, CtECCommonRow>> threadLocalIndexedRows = new ThreadLocal<>();
    
	public void resetResultBuilderTheadLocal() {
		Map<String, CtECCommonRow> indexedRows = new HashMap<String, CtECCommonRow>();
		threadLocalIndexedRows.set(indexedRows);
	}

    public CtEventCalcData doBuilder(String seriesDay, CtEventCalcData calcData, List<LinkedHashMap<String, Object>> transferedResult, CtCalcEventMeasureReport oneReport, int measureLength) {

        // 拼写detail_result字段
    	doBuildDetailResult(seriesDay, calcData, transferedResult, oneReport);
        log.info("doBuildDetailResult={}", JSON.toJSONString(calcData));

        // 拼写rollup_result字段
        this.doBuildRollupResult(calcData, oneReport);
        log.info("doBuildRollupResult={}", JSON.toJSONString(calcData));

        // 拼写total_detail_result字段
        this.doBuildTotalDetailResult(seriesDay, calcData, oneReport, measureLength);
        log.info("doBuildTotalDetailResult={}", JSON.toJSONString(calcData));

        // 拼写total_rollup_result字段
        this.doBuildTotalRollupResult(calcData, oneReport, measureLength);
        log.info("doBuildTotalDetailResult={}", JSON.toJSONString(calcData));

        return calcData;
    }

    private void doBuildTotalRollupResult(CtEventCalcData calcData, CtCalcEventMeasureReport oneReport, int measureLength) {
        // by_fields字段
        calcData.getRollupResult().setByFields(oneReport.getByFields());

        // total_rollup_result字段元素
        CtECCommonResult totalRollupResult = calcData.getTotalRollupResult();

        // total_detail_result字段元素
        CtECCommonResult totalDetailResult = calcData.getTotalDetailResult();

        // detail_result字段元素
        CtECCommonResult detailResult = calcData.getDetailResult();

        // series字段
        if (totalRollupResult.getSeries().size() == 0) {
            String seriesDay = "";
            if(CtCalcConsts.UNIT_TYPE_DAY.equals(oneReport.getUnit())
            		|| CtCalcConsts.UNIT_TYPE_WEEK.equals(oneReport.getUnit())
            		|| CtCalcConsts.UNIT_TYPE_MONTH.equals(oneReport.getUnit())) {
            	seriesDay = CtDateUtils.dateToString(oneReport.getCaclDate().getFromDate(), CtDateUtils.YYYY_MM_DD);
            } else {
            	seriesDay = CtDateUtils.dateToString(oneReport.getCaclDate().getFromDate());
            }
            totalRollupResult.getSeries().add(seriesDay);
        }

        //无效(未使用)的局部变量
        //int index = oneReport.getMeasureIndex();
        if (totalRollupResult.getRows().size() == 0) {
            totalRollupResult.getRows().add(new CtECCommonRow());
        }

        // 获取rows 此rows只操作第一个元素
        List<List<Double>> totalRollupResultValues = totalRollupResult.getRows().get(0).getValues();
        totalRollupResultValues.clear();

        //判断有多少天
        int daysLength = detailResult.getSeries().size();

        //判断一天有多少列
        int fieldsLength = measureLength;


        List<Double> differentDayValue = new ArrayList<>();
        //循环 天数 列数 累加
        for (int i = 0; i < fieldsLength; i++) {
            //统计不同天数下同类型的数值
        	Double differentEventValue = 0D;
            for (int j = 0; j < daysLength; j++) {
                //当前天数下同一种筛选类型
                if (totalDetailResult.getRows().get(0).getValues().size() > j) {
                    if (totalDetailResult.getRows().get(0).getValues().get(j).size() > i) {
                        differentEventValue = differentEventValue + totalDetailResult.getRows().get(0).getValues().get(j).get(i);
                    }
                }
            }
            differentDayValue.add(differentEventValue);
        }

        //需要一个变量把当前天数组合
        totalRollupResultValues.add(differentDayValue);
    }

    private void doBuildTotalDetailResult(String seriesTime, CtEventCalcData calcData, CtCalcEventMeasureReport oneReport, int measureLength) {
        // by_fields字段
        calcData.getRollupResult().setByFields(oneReport.getByFields());

        // total_detail_result字段元素
        CtECCommonResult totalDetailResult = calcData.getTotalDetailResult();

        // detail_result字段元素
        CtECCommonResult detailResult = calcData.getDetailResult();

        // series的index,从0开始
        int indexSeries = 0;
        // 填充series
        {
            // String seriesDay = CtDateUtils.dateToString(oneReport.getCaclDate().getFromDate());
            indexSeries = CtCalcRowsUtils.findListIndex(totalDetailResult.getSeries(), seriesTime);
            if (indexSeries < 0) {
                totalDetailResult.getSeries().add(seriesTime);
            }
        }

        if (totalDetailResult.getRows().size() == 0) {
            totalDetailResult.getRows().add(new CtECCommonRow());
        }

        // 获取Values 用于重新设值
        List<List<Double>> totalDetailResultValues = totalDetailResult.getRows().get(0).getValues();
        totalDetailResultValues.clear();

        //判断有多少不一样的事件行数
        int defaultEventNums = detailResult.getRows().size();

        //判断有多少天
        int daysLength = detailResult.getSeries().size();

        //判断一天有多少列
        int fieldsLength = measureLength;

        //循环 天数 列数 行数 累加
        for (int i = 0; i < daysLength; i++) {
            //统计当前天数下的数字
            List<Double> toDayValue = new ArrayList<>();
            for (int j = 0; j < fieldsLength; j++) {
                //当前天数下同一种筛选类型
            	Double toDayEventValue = 0D;
                for (int k = 0; k < defaultEventNums; k++) {
                    if (detailResult.getRows().size() > k) {
                        //当前天数下同一种筛选类型不同事件循环
                        List<List<Double>> values = detailResult.getRows().get(k).getValues();
                        List<Double> dayValues = values.get(i);
                        double itemValue = 0;
                        if (dayValues.size() != 0 || dayValues.size() > j) {
                            itemValue = dayValues.get(j);
                        }
                        toDayEventValue += itemValue;
                    }
                }
                toDayValue.add(toDayEventValue);
            }
            //需要一个变量把当前天数组合
            totalDetailResultValues.add(toDayValue);
        }

    }

    private void doBuildRollupResult(CtEventCalcData calcData, CtCalcEventMeasureReport oneReport) {
        // by_fields字段
        calcData.getRollupResult().setByFields(oneReport.getByFields());

        // rollupResult用于下面的series
        CtECRollupResult rollupResult = calcData.getRollupResult();

        // series字段
        if (rollupResult.getSeries().size() == 0) {
            String seriesDay = "";
            if(CtCalcConsts.UNIT_TYPE_DAY.equals(oneReport.getUnit())
            		|| CtCalcConsts.UNIT_TYPE_WEEK.equals(oneReport.getUnit())
            		|| CtCalcConsts.UNIT_TYPE_MONTH.equals(oneReport.getUnit())) {
            	seriesDay = CtDateUtils.dateToString(oneReport.getCaclDate().getFromDate(), CtDateUtils.YYYY_MM_DD);
            } else {
            	seriesDay = CtDateUtils.dateToString(oneReport.getCaclDate().getFromDate());
            }
            rollupResult.getSeries().add(seriesDay);
        }

        Map<String, CtECCommonRow> rows = threadLocalIndexedRows.get();
        Set<Entry<String, CtECCommonRow>> entries = rows.entrySet();
        //清空上一次结果
        rollupResult.getRows().clear();
        for (Entry<String, CtECCommonRow> entry : entries) {
            CtECCommonRow mapValue = entry.getValue();
            // 初始化 - CtECRollupRow
            CtECRollupRow rollupRow = new CtECRollupRow();
            rollupRow.setByValues(new ArrayList<>(mapValue.getByValues()));
            // 初始化 - 按measure(事件)累加 - 数组
            rollupRow.getValues().add(new ArrayList<Double>());
            rollupRow.getMaxValues().add(new ArrayList<Double>());
            rollupRow.getMinValues().add(new ArrayList<Double>());
            rollupRow.getAvgValues().add(new ArrayList<Double>());
            // 初始化 - 全部初始化为0.0
            for (int index = 0; index <= oneReport.getMaxMeasureIndex(); index++) {
                rollupRow.getValues().get(0).add(Double.valueOf(0));
                rollupRow.getMaxValues().get(0).add(Double.valueOf(0));
                rollupRow.getMinValues().get(0).add(Double.valueOf(0));
                rollupRow.getAvgValues().get(0).add(Double.valueOf(0));
            }
            // 按measure(事件)累加
            List<List<Double>> dayMeasureValues = mapValue.getValues();
            for (int measureIndex = 0; measureIndex <= oneReport.getMaxMeasureIndex(); measureIndex++) {
                //如果空串情况
                boolean minState = false;
                //是否0属性是默认值
                boolean defaultZero = true;
                for (int seriesIndex = 0; seriesIndex <= oneReport.getMaxSeriesIndex(); seriesIndex++) {
                    if (seriesIndex >= dayMeasureValues.size()) {
                        minState = true;
                        continue;
                    }
                    if (measureIndex >= dayMeasureValues.get(seriesIndex).size()) {
                        minState = true;
                        continue;
                    }
                    Double theMapItemV = dayMeasureValues.get(seriesIndex).get(measureIndex);
                    // 累加求和
                    List<Double> values = rollupRow.getValues().get(0);
                    Double tempV = theMapItemV + values.get(measureIndex);
                    values.set(measureIndex, tempV);
                    // 求最大值
                    List<Double> maxValues = rollupRow.getMaxValues().get(0);
                    if (maxValues.get(measureIndex) < theMapItemV) {
                        maxValues.set(measureIndex, theMapItemV);
                    }
                    // 求最小值
                    List<Double> minValues = rollupRow.getMinValues().get(0);
                    if (!minState) {
                        if (defaultZero) {
                            minValues.set(measureIndex, theMapItemV);
                            defaultZero = false;
                        }else{
                            if (minValues.get(measureIndex) > theMapItemV) {
                                minValues.set(measureIndex, theMapItemV);
                            }
                        }
                    }

                    // 求平均值
                    List<Double> avgValues = rollupRow.getAvgValues().get(0);
                    // tempV = values.get(measureIndex) / (oneReport.getMaxMeasureIndex() + 1);
                    tempV = values.get(measureIndex) / (oneReport.getMaxSeriesIndex() + 1);
                    avgValues.set(measureIndex, tempV);
                }
            }
            // 增加一行rollup数据
            rollupResult.getRows().add(rollupRow);
        }

        //填充num_rows与total_rows
        int rowsNum = rollupResult.getRows().size();
        rollupResult.setNumRows((long) rowsNum);
        rollupResult.setTotalRows((long) rowsNum);
    }

    private void doBuildDetailResult(String seriesTime, CtEventCalcData calcData, List<LinkedHashMap<String, Object>> queryResults, CtCalcEventMeasureReport oneReport) {
        // by_fields字段
        calcData.getDetailResult().setByFields(oneReport.getByFields());

        CtECCommonResult detailResult = calcData.getDetailResult();

        // series的index,从0开始
        int indexSeries = 0;
        // 1. 填充series
        {
            //String seriesDay = CtDateUtils.dateToString(oneReport.getCaclDate().getFromDate());
            indexSeries = CtCalcRowsUtils.findListIndex(detailResult.getSeries(), seriesTime);
            if (indexSeries < 0) {
                detailResult.getSeries().add(seriesTime);
                indexSeries = detailResult.getSeries().size() - 1;
            }
        }
        // 2. 填充rows
        for (LinkedHashMap<String, Object> oneRecord : queryResults) {
            // 2.1 检查oneRecord对应的row是否存,不存在,则新建一个
            List<String> byValues = new ArrayList<>();
            for (String oneByField : oneReport.getByFields()) {
                CtCalcPropertyType property = CtCalcPropertyUtils.getValueType(oneByField);
                String oneByValue = String.valueOf(oneRecord.get(property.getProperty()));
                // oneRow.getByValues().add(oneByValue);
                byValues.add(oneByValue);
            }
            
            String rowKey = CtCalcRowsUtils.buildDetailResultRowKey(byValues);
            CtECCommonRow oneRow = threadLocalIndexedRows.get().get(rowKey);
            if (null == oneRow) {
                oneRow = new CtECCommonRow();
                detailResult.getRows().add(oneRow);
                threadLocalIndexedRows.get().put(rowKey, oneRow);
            }
            // 2.2 填充 rows - by_values
            if (oneRow.getByValues().isEmpty()) {
                oneRow.getByValues().addAll(byValues);
            }
            // 确保ByValues与ByFields大小一致
            for (int index = oneRow.getByValues().size(); index < oneReport.getByFields().size(); index++) {
                oneRow.getByValues().add("");
            }
            // 2.3 填充 rows - values
            // 填充数组大小
            for (int dIndex = oneRow.getValues().size(); dIndex <= oneReport.getMaxSeriesIndex(); dIndex++) {
            	List<Double> measureValues = new ArrayList<Double>();
            	oneRow.getValues().add(measureValues);
                // 用0.0D填充子数据内容 (填充数组值，初始化均为零)
            	// 重点：不能覆盖上一次的内容
                for (int mIndex = measureValues.size(); mIndex <= oneReport.getMaxMeasureIndex(); mIndex++) {
                	measureValues.add(0D);
                }
            }
            // 查找对应series的index的数组
            List<Double> measureValues = oneRow.getValues().get(indexSeries);
            // 查找哪个measrue(分析事件)的index
            // Double measureValue = Double.valueOf(oneRecord.get("total").toString());
            Double measureValue = 0.0D;
            Object retObj = oneRecord.get(CtFieldConsts.FIELD_KEY_TOTAL);
            if(retObj != null) {
            	measureValue = Double.valueOf(retObj.toString());
            }
            measureValues.set(oneReport.getMeasureIndex(), measureValue);
        }

        //填充num_rows与total_rows
        int rowsNum = detailResult.getRows().size();
        detailResult.setNumRows((long) rowsNum);
        detailResult.setTotalRows((long) rowsNum);

    }

}
